#include "DmxServer.h"
#include <QDebug>
#include <QtNetwork>

#include "DmxSetter.h"
#include "SwitchWatcher.h"

DmxServer::DmxServer(DmxSetter *setter, QObject *parent)
	: QTcpServer(parent)
	, m_setter(setter)
{
	
}

void DmxServer::start(int outputPort)
{
	if(listen(QHostAddress::Any,outputPort))
	{
		qDebug() << "DmxServer: Listening on port"<<outputPort;
	}
	else
	{
		qDebug() << "DmxServer: [ERROR] Unable start server on port"<<outputPort;
	}
}

void DmxServer::incomingConnection(int socketDescriptor)
{
	DmxServerThread *thread = new DmxServerThread(socketDescriptor, this);
	connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
	connect(thread, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
	connect(thread, SIGNAL(sendDmx(DmxValueList)), m_setter, SLOT(setDmxChannels(DmxValueList)));
	connect(thread, SIGNAL(setSwitchMater(bool)), m_setter, SLOT(setSwitchMaster(bool)));
	connect(thread, SIGNAL(setSwitchOnProfile(DmxValueList)), m_setter, SLOT(setSwitchOnProfile(DmxValueList)));
	connect(m_setter->switchWatcher(), SIGNAL(switchToggled(bool)), thread, SLOT(switchToggled(bool)));
	
	//qDebug() << "DmxServer::incomingConnection: Client connected, disabling switch master";	
	//m_setter->setSwitchMaster(false);
	thread->start();
}

void DmxServer::clientDisconnected()
{
	qDebug() << "DmxServer::clientDisconnected: Setting switch master again";
	m_setter->setSwitchMaster(true);
}

/*********************************************************************************************/
/*********************************************************************************************/
/*********************************************************************************************/

DmxServerThread::DmxServerThread(int socketDescriptor, DmxServer *parent)
	: QThread(parent)
	, m_server(parent)
	, m_socketDescriptor(socketDescriptor)
{
	m_socket = new QTcpSocket();
}

void DmxServerThread::run()
{
	memset(&m_dataFrame, 0, DMX_SERVER_FRAME_SIZE);
	
	connect(m_socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
	connect(m_socket, SIGNAL(disconnected()), this, SLOT(quit()));
	connect(m_socket, SIGNAL(readyRead()), 	  this, SLOT(dataReady()));
	
	if(!m_socket->setSocketDescriptor(m_socketDescriptor)) 
	{
		emit error(m_socket->error());
		return;
	}
	
	qDebug() << "DmxServerThread: Connection from "<<m_socket->peerAddress().toString(); //, Socket Descriptor:"<<socketDescriptor;
	
	m_isConnected = true;
	
	// Tell the client the current state of the switch so client doesnt have to wait for the switch to change
	switchToggled(m_server->setter()->switchWatcher()->isSwitchOn());
	
	// Run event loop
	exec();
}

void DmxServerThread::switchToggled(bool flag)
{
	if(!m_isConnected)
		return;
		
	qDebug() << "DmxServerThread::switchToggled: "<<flag;
		
	m_dataFrame[0] = DmxServerFrame_NotifySwitchToggled;
	m_dataFrame[1] = flag ? 1:0;
	m_dataFrame[2] = 0;
	//sprintf((char*)&frameData,"%d %d %d\n",a,b,c);
	
	m_socket->write((char *)&m_dataFrame,DMX_SERVER_FRAME_SIZE);
}

// void DmxServerThread::dataReady()
// {
// 	int bytes = m_socket->readLine((char *)&m_dataFrame,DMX_SERVER_FRAME_SIZE);
// 	
// 	int tgt = DMX_SERVER_FRAME_SIZE-1;
// 	if(bytes < tgt)
// 		qDebug() << "DmxServerThread::dataReady: Read "<<bytes<<"bytes, expected: "<<tgt<<"bytes";
// 	else
// 	{
// 		int frameType = (int)m_dataFrame[0];
// 		if(frameType == DmxServerFrame_SendDmx ||
// 		   frameType == DmxServerFrame_SetSwitchOnProfile)
// 		{
// 			DmxValueList values;
// 			for(int i=1; i<NUM_DMX_CHANNELS+1; i++)
// 				values[i-1] = m_dataFrame[i];
// 				
// 			qDebug() << "DmxServerThread::dataReady: data value check at pos 1, 5: "
// 				<< (int)m_dataFrame[2]
// 				<< (int)m_dataFrame[6]
// 				<< ", and now in the values[] vector: "
// 				<< (int)values[1]
// 				<< (int)values[5];
// 			
// 			if(frameType == DmxServerFrame_SendDmx)
// 				emit sendDmx(values);
// 			else
// 				emit setSwitchOnProfile(values);
// 		}
// 		else
// 		if(frameType == DmxServerFrame_SetSwitchMaster)
// 		{
// 			bool isMaster = ((int)m_dataFrame[1]) == 1;
// 			emit setSwitchMater(isMaster);
// 		}
// 		else
// 		{
// 			qDebug() << "DmxServerThread::dataReady: Unknown frame type: "<<frameType; 
// 		}
// 	}
// }

void DmxServerThread::dataReady()
{
	QByteArray bytes = m_socket->readAll();
	//qDebug() << "DmxClient::dataReady(): Reading from socket:"<<m_socket<<", read:"<<bytes.size()<<" bytes"; 
	if(bytes.size() > 0)
	{
		m_dataBlock.append(bytes);
//		qDebug() << "dataReady(), read bytes:"<<bytes.count()<<", buffer size:"<<m_dataBlock.size();
		
		processBlock();
	}
}

void DmxServerThread::processBlock()
{
	while(m_dataBlock.size() >= DMX_SERVER_FRAME_SIZE)
	{
		QByteArray header = m_dataBlock.left(DMX_SERVER_FRAME_SIZE);
		m_dataBlock.remove(0,DMX_SERVER_FRAME_SIZE);
		
		const char *data = header.constData();

		int frameType = (int)data[0];
		if(frameType == DmxServerFrame_SendDmx ||
		   frameType == DmxServerFrame_SetSwitchOnProfile)
		{
			DmxValueList values;
			for(int i=1; i<NUM_DMX_CHANNELS+1; i++)
				values[i-1] = data[i];
				
// 			qDebug() << "DmxServerThread::dataReady: data value check at pos 1, 5: "
// 				<< (int)data[5]
// 				<< ", and now in the values[] vector: "
// 				<< (int)values[4];
			
			if(frameType == DmxServerFrame_SendDmx)
			{
				//qDebug() << "DmxServerThread::dataReady: emitting sendDmx()";
				emit sendDmx(values);
			}
			else
				emit setSwitchOnProfile(values);
		}
		else
		if(frameType == DmxServerFrame_SetSwitchMaster)
		{
			bool isMaster = ((int)data[1]) == 1;
			qDebug() << "DmxServerThread::processBlock(): DmxServerFrame_SetSwitchMaster: isMaster:"<<isMaster; 
			emit setSwitchMater(isMaster);
		}
		else
		{
			qDebug() << "DmxServerThread::processBlock: Unknown frame type: "<<frameType; 
		}
	}
	
	/// This is an attempt to "skip" streams to make it more realtime
	m_dataBlock.clear();
}


DmxServerThread::~DmxServerThread()
{
	if(m_isConnected)
	{
		m_socket->abort();
		m_isConnected = false;
	}
	
	delete m_socket;
	m_socket = 0;
}
